
import 'dart:async';
import 'dart:io';

import 'package:flutter/services.dart';

class Appavailability {
  static const MethodChannel _channel =
      const MethodChannel('appavailability');

  static Future<String> get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  /// Check if an app is available with the given [uri] scheme.
  ///
  /// Returns a [Map<String, String>] containing info about the App or throws a [PlatformException]
  /// if the app isn't found.
  ///
  /// The returned [Map] has a form like this:
  /// ```dart
  /// {
  ///   "app_name": "",
  ///   "package_name": "",
  ///   "versionCode": "",
  ///   "version_name": ""
  /// }
  static Future<AppInfo?> checkAvailability(String uri) async {
    Map<String, dynamic> args = <String, dynamic>{};
    args.putIfAbsent('uri', () => uri);

    if (Platform.isAndroid) {
      Map<dynamic, dynamic> app = await _channel.invokeMethod("checkAvailability", args);
      return AppInfo(app["app_name"],app["package_name"]);
    }
    else if (Platform.isIOS) {
      bool appAvailable = await _channel.invokeMethod("checkAvailability", args);
      if (!appAvailable) {
        throw PlatformException(code: "", message: "App not found $uri");
      }
      return AppInfo("",uri);
    }

    return null;
  }

  /// Only for **Android**.
  ///
  /// Get the list of all installed apps, where
  /// each app has a form like [checkAvailability()].
  static Future<List<AppInfo>> getInstalledApps() async {
    List<dynamic>? apps = await _channel.invokeMethod("getInstalledApps");
    if (apps != null && apps is List) {
      List<AppInfo> list = [];
      for (var app in apps) {
        if (app is Map) {
          list.add(AppInfo(app["app_name"], app["package_name"]));
        }
      }

      return list;
    }
    return new List.empty();
  }

  /// Only for **Android**.
  ///
  /// Check if the app is enabled or not with the given [uri] scheme.
  ///
  /// If the app isn't found, then a [PlatformException] is thrown.
  static Future<bool> isAppEnabled(String uri) async {
    Map<String, dynamic> args = <String, dynamic>{};
    args.putIfAbsent('uri', () => uri);
    return await _channel.invokeMethod("isAppEnabled", args);
  }

  /// Launch an app with the given [uri] scheme if it exists.
  ///
  /// If the app app isn't found, then a [PlatformException] is thrown.
  static Future<void> launchApp(String uri) async {
    Map<String, dynamic> args = <String, dynamic>{};
    args.putIfAbsent('uri', () => uri);
    if (Platform.isAndroid) {
      await _channel.invokeMethod("launchApp", args);
    }
    else if (Platform.isIOS) {
      bool appAvailable = await _channel.invokeMethod("launchApp", args);
      if (!appAvailable) {
        throw PlatformException(code: "", message: "App not found $uri");
      }
    }

  }


  static Future<void> launch(String uri,{Map<String, String> headers = const <String, String>{}}) async {
    Map<String, dynamic> args = <String, dynamic>{};
    args.putIfAbsent('uri', () => uri);
    args.putIfAbsent('headers', () => headers);
    if (Platform.isAndroid) {
      await _channel.invokeMethod("launch", args);
    }
    else if (Platform.isIOS) {
      bool appAvailable = await _channel.invokeMethod("launchApp", args);
      if (!appAvailable) {
        throw PlatformException(code: "", message: "App not found $uri");
      }
    }

  }

  static Future<void> launchAppDetail(String uri,String packageName) async {
    Map<String, dynamic> args = <String, dynamic>{};
    args.putIfAbsent('uri', () => uri);
    args.putIfAbsent('packageName', () => packageName);
    if (Platform.isAndroid) {
      await _channel.invokeMethod("launchAppDetail", args);
    }
    else if (Platform.isIOS) {
      bool appAvailable = await _channel.invokeMethod("launchApp", args);
      if (!appAvailable) {
        throw PlatformException(code: "", message: "App not found $uri");
      }
    }
  }
}

class AppInfo{
  String appName;
  String packageName;

  AppInfo(this.appName,this.packageName);
}
